<template>
  <div class="yd-carousel" :style="{height}" @mouseenter="mouseEnter" @mouseleave="mouseLeave">
    <div class="inner">
      <slot></slot>
      <carDirector v-if="director" v-show="dirShow" @dirClick="dirClick"></carDirector>
      <carDots
        v-if="dots"
        :itemLen="itemLen"
        :currentIndex="currentIndex"
        :dotBgColor="dotBgColor"
        @dotClick="dotClick"
      ></carDots>
    </div>
  </div>
</template>

<script>
import {
  reactive,
  toRefs,
  onMounted,
  onBeforeUnmount,
  getCurrentInstance
} from "vue";
import carDirector from "./director";
import carDots from "./dots";
export default {
  name: "Carousel",
  components: {
    carDirector,
    carDots
  },
  props: {
    height: {
      type: String,
      default: "300px"
    },
    autoplay: {
      type: Boolean,
      default: true
    },
    duration: {
      type: Number,
      default: 3000
    },
    initial: {
      type: Number,
      default: 0
    },
    dots: {
      type: Boolean,
      default: true
    },
    director: {
      type: Boolean,
      default: true
    },
    dotBgColor: {
      type: String,
      default: "#fff"
    }
  },
  setup(props) {
    const instance = getCurrentInstance();
    const state = reactive({
      currentIndex: props.initial,
      itemLen: 0,
      dirShow: false,
      animationOver: true,
      dir: "next"
    });
    let t = null;
    const autoPlay = () => {
      if (props.autoplay) {
        t = setInterval(() => {
          setIndex("next");
        }, props.duration);
      }
    };
    const setIndex = dir => {
      switch (dir) {
        case "next":
          // 过渡动画完毕再执行
          if (state.animationOver) {
            state.currentIndex += 1;
            if (state.currentIndex === state.itemLen) {
              state.currentIndex = 0;
            }
            state.animationOver = false;
            setTimeout(() => {
              state.animationOver = true;
            }, 500);
          }
          break;
        case "prev":
          if (state.animationOver) {
            state.dir = "prev";
            state.currentIndex -= 1;
            if (state.currentIndex === -1) {
              state.currentIndex = state.itemLen - 1;
            }
            state.animationOver = false;
            setTimeout(() => {
              state.dir = "next";
              state.animationOver = true;
            }, 500);
          }
          break;
        default:
          break;
      }
    };
    const mouseEnter = () => {
      handleClearInterval();
      state.dirShow = true;
    };
    const mouseLeave = () => {
      autoPlay();
      state.dirShow = false;
    };
    const handleClearInterval = () => {
      clearInterval(t);
      t = null;
    };
    const dirClick = dir => {
      setIndex(dir);
    };
    const dotClick = index => {
      if (index < state.currentIndex) {
        state.dir = "prev";
      } else {
        state.dir = "next";
      }
      state.currentIndex = index;
    };
    const prev = () => {
      manualChange("prev");
    };
    const next = () => {
      manualChange("next");
    };
    const manualChange = dir => {
      let timer = null;
      function animation() {
        if (state.animationOver == true) {
          setIndex(dir);
          clearTimeout(timer);
          timer = null;
        } else {
          timer = setTimeout(animation, 0);
          clearTimeout(timer);
        }
      }
      animation();
    };
    onMounted(() => {
      state.itemLen = instance.slots.default()[0].children.length;
      autoPlay();
    });
    onBeforeUnmount(() => {
      handleClearInterval();
    });
    return {
      ...toRefs(state),
      mouseEnter,
      mouseLeave,
      handleClearInterval,
      dirClick,
      dotClick,
      prev,
      next
    };
  }
};
</script>

<style lang="scss" scoped>
.yd-carousel {
  width: 100%;
  height: 100%;
  .inner {
    position: relative;
    width: 100%;
    height: 100%;
    overflow: hidden;
  }
}
</style>